/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.silverpeas.core.admin;

import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.admin.user.model.ProfileInst;
import org.apache.commons.io.IOUtils;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.silverpeas.core.admin.service.Administration;
import org.silverpeas.core.persistence.jdbc.sql.JdbcSqlQuery;
import org.silverpeas.core.test.WarBuilder4LibCore;
import org.silverpeas.core.test.integration.rule.DbSetupRule;
import org.silverpeas.core.util.Charsets;
import org.silverpeas.kernel.util.StringUtil;

import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.util.*;
import java.util.logging.Logger;

import static org.silverpeas.core.admin.service.RightAssignationContext.MODE.COPY;
import static org.silverpeas.core.admin.service.RightAssignationContext.MODE.REPLACE;
import static org.junit.Assert.fail;

@RunWith(Arquillian.class)
public class AssignRightIT {

  private static final String SCRIPTS_PATH =
      "/" + AssignRightIT.class.getPackage().getName().replaceAll("\\.", "/");

  private final static boolean BUT_NOT_RIGHT_OBJECTS = false;
  private final static boolean WITH_RIGHT_OBJECTS = true;

  private final static String G1_D0 = "1";
  private final static String GROUP_THAT_CONTAINS_DIRECTLY_USER_A = "3";
  private final static String G2_D1 = "10";
  private final static String GROUP_NO_RIGHTS = "26";
  private final static String USER_A = "1";
  private final static String USER_B = "2";
  private final static String USER_NO_RIGHTS = "38";

  private final static String WRITER_PROFILE_ID_OF_KMELIA = "11";
  private final static String WRITER_PROFILE_ID_OF_KMELIA_SUB_NODE = "911";

  private final static String AUTHOR = null;

  @Inject
  private Administration administrationService;

  @Rule
  public DbSetupRule dbSetupRule =
      DbSetupRule.createTablesFrom(SCRIPTS_PATH + "/create-assign-rights-database.sql")
          .loadInitialDataSetFrom(SCRIPTS_PATH + "/insert-assign-rights-dataset.sql");

  @Before
  public void setUp() throws Exception {
    try {
      verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
    } catch (Throwable t) {
      Logger.getAnonymousLogger().severe("FAILED ON INITIAL DATA VERIFICATION");
      throw new RuntimeException(t);
    }
  }

  @After
  public void tearDown() throws Exception {
    administrationService.reloadCache();
  }

  @Deployment
  public static Archive<?> createTestArchive() {
    return WarBuilder4LibCore.onWarForTestClass(AssignRightIT.class)
        .addCommonBasicUtilities()
        .addPublicationTemplateFeatures()
        .addSilverpeasExceptionBases().testFocusedOn(
            (warBuilder) -> ((WarBuilder4LibCore) warBuilder).addAdministrationFeatures()).build();
  }

  /*
  FUNCTIONAL CASES - VERY HEADACHE CASES:
  A user is in a sub group of a group and the group has right on component that handles node
  structure (kmelia for example).
  This user has direct right on a sub node of the component and a direct right on the component.
  When the direct right on the component is removed for the user, as it is part of the sub group
  of the group that has access to the component, the direct right on the node of the component
  must not be deleted.
   */

  @Test
  public void testDirectKmeliaSubNodeRightMustNotBeDeletedIfUserIsInGroupThatHasKmeliaAccess()
      throws AdminException {
    // Adding writer right on sub node of kmelia to user A
    ProfileInst profileInst =
        administrationService.getProfileInst(WRITER_PROFILE_ID_OF_KMELIA_SUB_NODE);
    profileInst.addUser(USER_A);
    administrationService.updateProfileInst(profileInst);

    // Verifying that the right has been added successfully
    verifyCurrentDirectRights("test-assign-rights-expected-userAWithKmeliaSubNodeRight.txt");

    // Removing the writer right on kmelia from user A
    profileInst = administrationService.getProfileInst(WRITER_PROFILE_ID_OF_KMELIA);
    profileInst.removeUser(USER_A);
    administrationService.updateProfileInst(profileInst);

    // Verifying that the writer right on component has been removed,
    // but not the one on the sub node as the user is in a group that has yet right on kmelia
    // component
    verifyCurrentDirectRights(
        "test-assign-rights-expected-userAWithKmeliaSubNodeRight-directRightRemovedFromKmelia.txt");
  }

  @Test
  public void testDirectKmeliaSubNodeRightMustNotBeDeletedIfUserHasYetDirectKmeliaAccess()
      throws AdminException {
    // Adding writer right on sub node of kmelia to user A
    ProfileInst profileInst =
        administrationService.getProfileInst(WRITER_PROFILE_ID_OF_KMELIA_SUB_NODE);
    profileInst.addUser(USER_A);
    administrationService.updateProfileInst(profileInst);

    // Verifying that the right has been added successfully
    verifyCurrentDirectRights("test-assign-rights-expected-userAWithKmeliaSubNodeRight.txt");

    // Removing user A from the group that has access to kmelia
    administrationService.removeUserFromGroup(USER_A, GROUP_THAT_CONTAINS_DIRECTLY_USER_A);

    // Verifying that no right has been removed as USER_A has yet a role at component instance level
    verifyCurrentDirectRights("test-assign-rights-expected-userAWithKmeliaSubNodeRight.txt");
  }

  @Test
  public void testDirectKmeliaSubNodeRightMustNotBeDeletedIfUserHasNoMoreAccessOnKmelia()
      throws AdminException {
    // Adding writer right on sub node of kmelia to user A
    ProfileInst profileInst =
        administrationService.getProfileInst(WRITER_PROFILE_ID_OF_KMELIA_SUB_NODE);
    profileInst.addUser(USER_A);
    administrationService.updateProfileInst(profileInst);

    // Removing user A from the group that has access to kmelia
    administrationService.removeUserFromGroup(USER_A, GROUP_THAT_CONTAINS_DIRECTLY_USER_A);

    // Verifying that the right has been added successfully
    verifyCurrentDirectRights("test-assign-rights-expected-userAWithKmeliaSubNodeRight.txt");

    // Removing the writer right on kmelia from user A
    profileInst = administrationService.getProfileInst(WRITER_PROFILE_ID_OF_KMELIA);
    profileInst.removeUser(USER_A);
    administrationService.updateProfileInst(profileInst);

    // Verifying that the writer right on component has been removed,
    // but the rights on the sub nodes are kept even if the the user is no more in a group that has
    // yet right on kmelia component
    verifyCurrentDirectRights("test-assign-rights-expected-userAWithKmeliaSubNodeRight" +
        "-removedFromGoupG1_2AndDirectRightRemovedFromKmelia.txt");
  }

  /*
  FUNCTIONAL CASES - GROUP to USER
   */

  @Test
  public void testAssignFromGroup1ToUserAByCopyModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(COPY, G1_D0, USER_A, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToUser_A-CopyMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup1ToUserAByCopyModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(COPY, G1_D0, USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToUser_A-CopyMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup1ToUserBByReplaceModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(REPLACE, G1_D0, USER_B, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToUser_B-ReplaceMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup1ToUserBByReplaceModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(REPLACE, G1_D0, USER_B, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToUser_B-ReplaceMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromGroupNoRightsToUserAByCopyModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(COPY, GROUP_NO_RIGHTS, USER_A, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
  }

  @Test
  public void testAssignFromGroupNoRightsToUserBByReplaceModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromGroupToUser(REPLACE, GROUP_NO_RIGHTS, USER_B, BUT_NOT_RIGHT_OBJECTS,
            AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupNoRightsToUser_B-ReplaceMode-ButNotObjectRights.txt");
  }

  /*
  FUNCTIONAL CASES - GROUP to GROUP
   */

  @Test
  public void testAssignFromGroup1ToGroup2AByCopyModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(COPY, G1_D0, G2_D1, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToGroupG2-CopyMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup1ToGroup2AByCopyModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(COPY, G1_D0, G2_D1, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToGroupG2-CopyMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup2ToGroupAByReplaceModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(REPLACE, G2_D1, G1_D0, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG2ToGroupG1-ReplaceMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromGroup1ToGroup2AByReplaceModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(REPLACE, G1_D0, G2_D1, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupG1ToGroupG2-ReplaceMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromGroupNoRightsToGroupG1ByCopyModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(COPY, GROUP_NO_RIGHTS, G1_D0, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
  }

  @Test
  public void testAssignFromGroupNoRightsToGroupG1ByReplaceModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(REPLACE, GROUP_NO_RIGHTS, G1_D0, BUT_NOT_RIGHT_OBJECTS,
            AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-GroupNoRightsToGroupG1-ReplaceMode-ButNotObjectRights.txt");
  }

  /*
  FUNCTIONAL CASES - USER to GROUP
   */

  @Test
  public void testAssignFromUserBToGroupG2ByCopyModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(COPY, USER_B, G2_D1, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToGroupG2-CopyMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromUserBToGroupG2ByCopyModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(COPY, USER_B, G2_D1, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToGroupG2-CopyMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromUserBToGroupG1ByReplaceModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(REPLACE, USER_B, G1_D0, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToGroupG1-ReplaceMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromUserBToGroupG1ByReplaceModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(REPLACE, USER_B, G1_D0, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToGroupG1-ReplaceMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromUserNoRightsToGroupG2ByCopyModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(COPY, USER_NO_RIGHTS, G2_D1, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
  }

  @Test
  public void testAssignFromUserNoRightsToGroupG1ByReplaceModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromUserToGroup(REPLACE, USER_NO_RIGHTS, G1_D0, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserNoRightsToGroupG1-ReplaceMode-ButNotObjectRights.txt");
  }

  /*
  FUNCTIONAL CASES - USER to USER
   */

  @Test
  public void testAssignFromUserBToUserAByCopyModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToUser(COPY, USER_B, USER_A, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToUserA-CopyMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromUserBToUserAByCopyModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToUser(COPY, USER_B, USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToUserA-CopyMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromUserAToUserBByReplaceModeButNotObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToUser(REPLACE, USER_A, USER_B, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserAToUserB-ReplaceMode-ButNotObjectRights.txt");
  }

  @Test
  public void testAssignFromUserBToUserAByReplaceModeWithObjectRights() throws AdminException {
    administrationService
        .assignRightsFromUserToUser(REPLACE, USER_B, USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserBToUserA-ReplaceMode-WithObjectRights.txt");
  }

  @Test
  public void testAssignFromUserNoRightsToUserBByCopyModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromUserToUser(COPY, USER_NO_RIGHTS, USER_B, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
  }

  @Test
  public void testAssignFromUserNoRightsToUserBByReplaceModeButNotObjectRights()
      throws AdminException {
    administrationService
        .assignRightsFromUserToUser(REPLACE, USER_NO_RIGHTS, USER_B, BUT_NOT_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights(
        "test-assign-rights-expected-UserNoRightsToUserB-ReplaceMode-ButNotObjectRights.txt");
  }

  /*
  LIMIT CASES
   */

  @Test
  public void testSameSourceAndTarget() throws AdminException {
    administrationService
        .assignRightsFromGroupToGroup(COPY, G1_D0, G1_D0, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
    administrationService
        .assignRightsFromUserToUser(COPY, USER_A, USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    verifyCurrentDirectRights("test-assign-rights-expected-initial.txt");
  }

  @Test
  public void testAssignFromNotDefinedNullSource() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, null, USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedEmptySource() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, "", USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedSpacesSource() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, "   ", USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedNullStringSource() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, "null", USER_A, WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedNullTarget() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, USER_A, null, WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedEmptyTarget() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, USER_A, "", WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedSpacesTarget() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, USER_A, "   ", WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  @Test
  public void testAssignFromNotDefinedNullStringTarget() throws AdminException {
    try {
      administrationService
          .assignRightsFromGroupToUser(COPY, USER_A, "null", WITH_RIGHT_OBJECTS, AUTHOR);
    } catch (AdminException e) {
      if (e.getCause() instanceof IllegalArgumentException) {
        return;
      }
    }
    fail("IllegalArgumentException should be thrown");
  }

  /**
   * Centralization of verification.<br>
   * <p>
   * The mechanism is the following:<br>
   * <p>
   * the given parameters represents the name of the file that contains the expected result that
   * must return the method {@link #getCurrentDirectRights()}.<br> Normally, each lines starts with
   * a number as the first data is the domain id. So, in order to give the possibility to annotate
   * the file (for comprehension for example), each line of the file that does not start with a
   * number is ignored.<br> If the file content is equal to the result of the query execution, the
   * test is successfully verified.<br> If not, the different lines between the file content and the
   * query result are logged to the console.<br> The lines of current query result and those of the
   * expected ones (from the file) are sorted by alphabetic mode.
   * </p>
   *
   * @param fileNameOfExpectedResult result
   */
  private void verifyCurrentDirectRights(String fileNameOfExpectedResult) {
    StringReader current = new StringReader(getCurrentDirectRights());
    StringReader expected = new StringReader(getFileContent(fileNameOfExpectedResult));
    List<String> currentLines = IOUtils.readLines(current);
    List<String> expectedLines = IOUtils.readLines(expected);
    Iterator<String> expectedLinesIt = expectedLines.iterator();
    while (expectedLinesIt.hasNext()) {
      String currentExpectedLine = expectedLinesIt.next();
      byte[] firstChar = new byte[]{currentExpectedLine.getBytes()[0]};
      if (!StringUtil.isInteger(new String(firstChar))) {
        // The line does not start with a number, it must be ignored in verification process.
        expectedLinesIt.remove();
      }
    }
    List<String> leavingCurrentLines = new ArrayList<>(currentLines);
    leavingCurrentLines.removeAll(expectedLines);
    List<String> leavingExpectedLines = new ArrayList<>(expectedLines);
    leavingExpectedLines.removeAll(currentLines);
    boolean areContentEquals = leavingCurrentLines.isEmpty() && leavingExpectedLines.isEmpty();
    String message = "";
    if (!leavingCurrentLines.isEmpty()) {
      Collections.sort(leavingCurrentLines);
      message += "Current lines that are not in expected ones:\n" +
          String.join("\n", leavingCurrentLines);
    }
    if (!leavingExpectedLines.isEmpty()) {
      if (StringUtil.isDefined(message)) {
        message += "\n";
      }
      Collections.sort(leavingExpectedLines);
      message += "Expected lines that are not in current ones:\n" +
          String.join("\n", leavingExpectedLines);
    }
    if (!areContentEquals) {
      fail("\n" + message);
    }
  }

  /**
   * This method execute a SQL Query on the database (with the connection of the test) to extract
   * the list of all direct rights (inherited or not) assigned to users and groups.<br> The executed
   * query returns 3 columns and the two firsts columns has always the same number of characters
   * (spaces are added after data to obtain the total number of characters that must have the
   * column). For example, the first column always returns 40 characters. <br> The composition of
   * the columns is the following (separated by tabulation character):
   * <ul>
   * <li>Column 1: the domain identifier of the group or the user</li>
   * <li>
   * Column 2: the following data separated by " - "
   * <ul>
   * <li>(G) if the line aims a group, (U) if the line aims a user</li>
   * <li>the name of the group or of the user</li>
   * </ul>
   * </li>
   * <li>
   * Column 3: the following data separated by " - " expected for the two first data that are
   * separated by a space character
   * <ul>
   * <li>* in order to indicate that the right is not an inherited one, ^ for inherited one</li>
   * <li>
   * the type of resource aimed by the right:
   * <ul>
   * <li>SPACE: the right concerns a space</li>
   * <li>COMPONENT: the right concerns a component</li>
   * <li>COMPONENT-OBJECT: the right concerns an object managed by a component</li>
   * </ul>
   * </li>
   * <li>[name of the aimed role]@[name of the application or space according to the previous data
   * type][#[the name of the aime object if the previous data type is COMPONENT-OBJECT, in these
   * tests an OBJECT is always a node]]</li>
   * </ul>
   * </li>
   * </ul>
   *
   * @return a string that represents the result of the query execution.
   */
  private String getCurrentDirectRights() {
    try {
      final StringBuilder result = new StringBuilder();
      JdbcSqlQuery.create(getFileContent("select-verifying-direct-rights.sql")).execute(row -> {
        if (result.length() > 0) {
          result.append("\n");
        }
        for (int i = 0; i < row.getMetaData().getColumnCount(); i++) {
          if (i > 0) {
            result.append("\t");
          }
          result.append(row.getString(i + 1));
        }
        return null;
      });
      return result.toString();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  private String getFileContent(String fileName) {
    try (InputStream fileStream = getClass().getResourceAsStream(fileName)) {
      return String.join("\n", IOUtils.readLines(Objects.requireNonNull(fileStream),
          Charsets.UTF_8));
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }
}